﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Data.SqlClient;

using Fuse8.DomainFramework.Common;
using Fuse8.DomainFramework.DataAccess.SqlDatabase;

using Fuse8.ContentManagementFramework.Domain;
using Fuse8.ContentManagementFramework.Domain.Commands;

namespace Fuse8.ContentManagementFramework.DataAccess.SqlAccess.Mappers
{
    internal class CmsMediaDataMapper : BaseSqlEntityDataMapper<CmsMedia, int>
    {
        private static BaseSqlEntityDataMapper<CmsMedia, int> _based = new BaseSqlEntityDataMapper<CmsMedia, int>(new string[] { "EntityMetaInformation", "SiteGroup", "Site", "SiteCategory", "TotalMediaContent", "SubFolders" });

        private static Dictionary<string, Func<object, IList<SqlParameter>>> _mappersTo = new Dictionary<string, Func<object, IList<SqlParameter>>>();

        static CmsMediaDataMapper()
        {
            _mappersTo.Add("cms_sp_MediaSelectAll",
                (p) =>
                {
                    return _based.MapTo("cms_sp_MediaSelectAll", p, false);
                });
            _mappersTo.Add("cms_sp_MediaSelectOne",
                (p) =>
                {
                    return _based.MapTo("cms_sp_MediaSelectOne", p, false);
                });
            _mappersTo.Add("cms_sp_MediaAdd",
                (p) =>
                {
                    return _based.MapTo("cms_sp_MediaAdd", p, true);
                });
            _mappersTo.Add("cms_sp_MediaSave", CreateMapperForUpdate);
        }

        public CmsMediaDataMapper()
            : base()
        { }

        public override IList<SqlParameter> MapTo(string sp, object parameter, bool isForCreate)
        {
            Guard.ArgumentNotEmpty(sp, "sp");
            Guard.ArgumentNotNull(parameter, "parameter");

            return _mappersTo.ContainsKey(sp) ?
                _mappersTo[sp](parameter) :
                _based.MapTo(sp, parameter, isForCreate);
        }

        public override CmsMedia MapFrom(string sp, SqlDataReader reader)
        {
            Guard.ArgumentNotEmpty(sp, "sp");
            Guard.ArgumentNotNull(reader, "reader");

            var result = new CmsMedia
                             {
                                 Id = reader.GetInt32(reader.GetOrdinal("MediaId")),
                                 SiteId = !reader.IsDBNull(reader.GetOrdinal("SiteId"))
                                              ? reader.GetInt32(reader.GetOrdinal("SiteId"))
                                              : new Nullable<int>(),
                                 SiteGroupId = !reader.IsDBNull(reader.GetOrdinal("SiteGroupId"))
                                                   ? reader.GetInt32(reader.GetOrdinal("SiteGroupId"))
                                                   : new Nullable<int>(),
                                 FolderName = reader.GetString(reader.GetOrdinal("FolderName")),
                                 Description = !reader.IsDBNull(reader.GetOrdinal("Description"))
                                                   ? reader.GetString(reader.GetOrdinal("Description"))
                                                   : null,
                                 CreatedBy = reader.GetInt32(reader.GetOrdinal("CreatedBy")),
                                 DateCreated = reader.GetDateTime(reader.GetOrdinal("DateCreated")),
                                 LastUpdatedBy = !reader.IsDBNull(reader.GetOrdinal("LastUpdatedBy"))
                                                     ? reader.GetInt32(reader.GetOrdinal("LastUpdatedBy"))
                                                     : new Nullable<int>(),
                                 DateLastUpdated = !reader.IsDBNull(reader.GetOrdinal("DateLastUpdated"))
                                                       ? reader.GetDateTime(reader.GetOrdinal("DateLastUpdated"))
                                                       : new Nullable<DateTime>(),
                                 TotalMediaContent = reader.GetInt32(reader.GetOrdinal("TotalMediaContent")),
                                 ParentMediaId = !reader.IsDBNull(reader.GetOrdinal("ParentMediaId"))
                                                     ? reader.GetInt32(reader.GetOrdinal("ParentMediaId"))
                                                     : new int?(),
                                 Level = reader.GetInt32(reader.GetOrdinal("Level"))
                             };

            return result;
        }

        public override CmsMedia MapFromMulti(string sp, SqlDataReader reader, CmsMedia stepEntity, int index)
        {
            Guard.ArgumentNotEmpty(sp, "sp");
            Guard.ArgumentNotNull(reader, "reader");
            
            if (index == 0)
            {
                stepEntity = GetCmsMedia(reader);
                stepEntity.Description = !reader.IsDBNull(reader.GetOrdinal("Description"))
                                             ? reader.GetString(reader.GetOrdinal("Description"))
                                             : null;
            }
            else if (index == 1)
            {
                var stepMediaContent = new CmsMediaContent
                {
                    Id = reader.GetInt32(reader.GetOrdinal("MediaContentId")),
                    MediaId = reader.GetInt32(reader.GetOrdinal("MediaId")),
                    SiteId = !reader.IsDBNull(reader.GetOrdinal("SiteId")) ?
                        reader.GetInt32(reader.GetOrdinal("SiteId")) :
                        new Nullable<int>(),
                    SiteGroupId = !reader.IsDBNull(reader.GetOrdinal("SiteGroupId")) ?
                        reader.GetInt32(reader.GetOrdinal("SiteGroupId")) :
                        new Nullable<int>(),
                    MediaContentName = reader.GetString(reader.GetOrdinal("MediaContentName")),
                    MetaCode = reader.GetString(reader.GetOrdinal("MetaCode")),
                    Description = !reader.IsDBNull(reader.GetOrdinal("Description")) ?
                        reader.GetString(reader.GetOrdinal("Description")) :
                        null,
                    CreatedBy = reader.GetInt32(reader.GetOrdinal("CreatedBy")),
                    DateCreated = reader.GetDateTime(reader.GetOrdinal("DateCreated")),
                    LastUpdatedBy = !reader.IsDBNull(reader.GetOrdinal("LastUpdatedBy")) ?
                        reader.GetInt32(reader.GetOrdinal("LastUpdatedBy")) :
                        new Nullable<int>(),
                    DateLastUpdated = !reader.IsDBNull(reader.GetOrdinal("DateLastUpdated")) ?
                       reader.GetDateTime(reader.GetOrdinal("DateLastUpdated")) :
                       new Nullable<DateTime>()                    
                };

                if (stepEntity.MediaContents == null)
                {
                    stepEntity.MediaContents = new CmsMediaContent[] { stepMediaContent };
                }
                else
                {
                    stepEntity.MediaContents = stepEntity.MediaContents.Concat(new CmsMediaContent[] { stepMediaContent }).ToList();
                }
            }
            else if (index == 2)
            {
                int mediaContentId = reader.GetInt32(reader.GetOrdinal("MediaContentId"));

                var stepMediaContent = stepEntity.MediaContents.FirstOrDefault(p => p.Id == mediaContentId);
                if (stepMediaContent != null)
                {
                    var stepMediaFile = new CmsMediaFile
                    {
                        Id = reader.GetInt32(reader.GetOrdinal("MediaFileId")),
                        IsPrimary = reader.GetBoolean(reader.GetOrdinal("IsPrimary")),
                        LinkedFileName = reader.GetString(reader.GetOrdinal("LinkedFileName")),
                        OriginalFileName = reader.GetString(reader.GetOrdinal("OriginalFileName")),
                        FileSize = reader.GetInt64(reader.GetOrdinal("FileSize")),
                        Height = !reader.IsDBNull(reader.GetOrdinal("Height")) ?
                            reader.GetInt32(reader.GetOrdinal("Height")) :
                            new Nullable<int>(),
                        Width = !reader.IsDBNull(reader.GetOrdinal("Width")) ?
                           reader.GetInt32(reader.GetOrdinal("Width")) :
                           new Nullable<int>()
                    };

                    if (!reader.IsDBNull(reader.GetOrdinal("MimeTypeId")))
                    {
                        stepMediaFile.MimeType = new CmsMimeType
                        {
                            Id = reader.GetInt32(reader.GetOrdinal("MimeTypeId")),
                            ContentType = reader.GetString(reader.GetOrdinal("ContentType")),
                            MimeTypeName = reader.GetString(reader.GetOrdinal("MimeTypeName")),
                            IsImage = !reader.IsDBNull(reader.GetOrdinal("IsImage")) ?
                                reader.GetBoolean(reader.GetOrdinal("IsImage")) :
                                false
                        };
                    }

                    if (stepMediaFile.IsPrimary)
                    {
                        stepMediaContent.MainFile = stepMediaFile;
                    }

                    if (stepMediaContent.LinkedFiles == null)
                    {
                        stepMediaContent.LinkedFiles = new CmsMediaFile[] { stepMediaFile };
                    }
                    else
                    {
                        stepMediaContent.LinkedFiles = stepMediaContent.LinkedFiles.Concat(new CmsMediaFile[] { stepMediaFile }).ToList();
                    }
                }
            }
            else if(index == 3 && sp.Equals("cms_sp_MediaSelectOne", StringComparison.OrdinalIgnoreCase))
            {
                var media = GetCmsMedia(reader);
                media.TotalMediaContent = !reader.IsDBNull(reader.GetOrdinal("TotalMediaContent"))
                                              ? reader.GetInt32(reader.GetOrdinal("TotalMediaContent"))
                                              : 0;
                if (stepEntity.SubFolders != null)
                {
                    stepEntity.SubFolders = stepEntity.SubFolders.Concat(new []{media}).ToList();
                }
                else
                {
                    stepEntity.SubFolders = new[] {media}.ToList();
                }
            }
            else
            {
                throw new InvalidOperationException(string.Format("Stored procedure {0} can't return more than {1} result", sp, index));
            }

            return stepEntity;
        }

        private static CmsMedia GetCmsMedia(SqlDataReader reader)
        {
            CmsMedia stepEntity = new CmsMedia
                                      {
                                          Id = reader.GetInt32(reader.GetOrdinal("MediaId")),
                                          SiteId = !reader.IsDBNull(reader.GetOrdinal("SiteId"))
                                                       ? reader.GetInt32(reader.GetOrdinal("SiteId"))
                                                       : new int?(),
                                          ParentMediaId = !reader.IsDBNull(reader.GetOrdinal("ParentMediaId"))
                                                                                                 ? reader.GetInt32(reader.GetOrdinal("ParentMediaId"))
                                                                                                 : new int?(),
                                          SiteGroupId = !reader.IsDBNull(reader.GetOrdinal("SiteGroupId"))
                                                            ? reader.GetInt32(reader.GetOrdinal("SiteGroupId"))
                                                            : new int?(),
                                          FolderName = reader.GetString(reader.GetOrdinal("FolderName")),                                 
                                          CreatedBy = reader.GetInt32(reader.GetOrdinal("CreatedBy")),
                                          DateCreated = reader.GetDateTime(reader.GetOrdinal("DateCreated")),
                                          LastUpdatedBy = !reader.IsDBNull(reader.GetOrdinal("LastUpdatedBy"))
                                                              ? reader.GetInt32(reader.GetOrdinal("LastUpdatedBy"))
                                                              : new int?(),
                                          DateLastUpdated = !reader.IsDBNull(reader.GetOrdinal("DateLastUpdated"))
                                                                ? reader.GetDateTime(reader.GetOrdinal("DateLastUpdated"))
                                                                : new DateTime?()
                                      };
            return stepEntity;
        }

        private static IList<SqlParameter> CreateMapperForUpdate(object parameter)
        {
            IList<SqlParameter> result = new List<SqlParameter>();

            var cmsUserGroup = parameter as CmsMedia;
            if (cmsUserGroup != null)
            {
                result.Add(new SqlParameter("Id", cmsUserGroup.Id));
                result.Add(new SqlParameter("SiteGroupId", cmsUserGroup.SiteGroupId));
                result.Add(new SqlParameter("SiteId", cmsUserGroup.SiteId));
                result.Add(new SqlParameter("FolderName", cmsUserGroup.FolderName));
                result.Add(new SqlParameter("Description", cmsUserGroup.Description));
                result.Add(new SqlParameter("LastUpdatedBy", cmsUserGroup.LastUpdatedBy));
                result.Add(new SqlParameter("DateLastUpdated", cmsUserGroup.DateLastUpdated));
                result.Add(new SqlParameter("ParentMediaId", cmsUserGroup.ParentMediaId));
            }

            return result;
        }
    }
}
